


import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.ArrayList;
import java.util.Locale;
import java.util.Random; 
import java.util.TreeSet;



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.MobiusTransform;
import pluginUtils.Point2D;
import pluginUtils.Point2DWithPotential;

import pluginUtils.PackCircle;


public class Eclair extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	

	private double xShift=0; 
	private double zShift=0; 
	
	

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	
	
	
	private void drawPoint(double x,double y){
		int intX=(int)(x*acoef+ccoef);
		int intY=(int)(y*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	private void drawPoint(Point2D p){
		int intX=(int)(p.getX()*acoef+ccoef);
		int intY=(int)(p.getY()*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
		
	private ArrayList<Point2DWithPotential> candidats=new ArrayList<Point2DWithPotential>(); 
	private ArrayList<Point2DWithPotential> charges=new ArrayList<Point2DWithPotential>();
	private int resolution=1000; 
	private double eta=2.0; 
	
	//choose a new candidate according to probabilities
	private Point2DWithPotential choose(){
		double[] auxi=new double[this.candidats.size()]; 
		// Find min and max
		double min=100; 
		double max=-100; 
		for(Point2DWithPotential p:candidats){
			double pot=p.getPotential(); 
			if(pot<min) min=pot; 
			if(pot>max) max=pot; 
		}
		// compute sum anf fill auxi array
		double sum=0; 
		int i=0; 
		for(Point2DWithPotential p:candidats){
			double pot=p.getPotential();
			double np=Math.pow((pot-min)/(max-min),eta); 
			sum+=np;   
			auxi[i++]=sum; 
		}
		// draw a random number between 0 and sum
		double cho=generator.nextDouble()*sum; 
		int j=0; 
		while(auxi[j]<sum) j++; 
		return candidats.remove(j); 
	}
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
		
		
		double limit=5; 
	
		setBounds(-limit,limit,-limit,limit); 
		setCoefs(); 
		
		double step=2*limit/resolution; 
	
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.BLACK);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.WHITE);
		primeIP.setLineWidth(5); 

		setProcessor("Verifying", primeIP);
		
		//drawLine(x0,0,x1,0);
		//drawLine(0,y0,0,y1);
		
		
		charges.add(new Point2DWithPotential(0,0,0)); 
		candidats.add(new Point2DWithPotential(step,step,1)); 
		candidats.add(new Point2DWithPotential(-step,step,1)); 
		candidats.add(new Point2DWithPotential(step,-step,1)); 
		candidats.add(new Point2DWithPotential(-step,step,1)); 
		candidats.add(new Point2DWithPotential(step,0,1)); 
		candidats.add(new Point2DWithPotential(-step,0,1)); 
		candidats.add(new Point2DWithPotential(0,-step,1)); 
		candidats.add(new Point2DWithPotential(0,step,1)); 
		
		for(int i=0;i<100;i++){
			Point2DWithPotential current=this.choose(); 
			charges.add(current); 
			Double np; 
			for(int k=-1;k<2;k++){
				for(int l=-1;l<2;l++)
					if((k!=0)||(l!=0)){
						Point2DWithPotential nx=new Point2DWithPotential(current.getX()+k*step,current.getY()+l*step); 
						if(!charges.contains(nx)&&(!candidats.contains(nx))){
							candidats.add(nx); 
						}//if
								
					}//if
			} // for k
			}// for i
		
		
		
		
		
		
	
	}	
}
	